package ch09
{
	import flash.display.Sprite;
	import flash.events.Event;

	import utils.Ball;

	/**
	 * 多物体弹性运动
	 * @author sjp
	 *
	 */
	public class Bubbles2 extends Sprite
	{
		private var balls:Array;
		private var numBalls:Number=30;
		private var bounce:Number=-0.5;
		private var spring:Number=0.05;
		private var gravity:Number=0.1;

		public function Bubbles2()
		{
			init();
		}

		private function init():void
		{
			balls=new Array();
			for (var i:uint=0; i < numBalls; i++)
			{
				var ball:Ball=new Ball(Math.random() * 30 + 20, Math.random() * 0xffffff);
				ball.x=Math.random() * stage.stageWidth;
				ball.y=Math.random() * stage.stageHeight;
				ball.vx=Math.random() * 6 - 3;
				ball.vy=Math.random() * 6 - 3;
				addChild(ball);
				balls.push(ball);
			}
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}

		/**
		 * 只要 ball0 与 ball1 发生了碰撞就会执行这段代码。
		 * 基本上与前面例子中的 centerBall 意思相近，只不是用 ball0 代替 centerBall。
		 * 求出需要它俩的夹角，然后计算目标点的 x,y 坐标，这就是 ball1 要到达的点，这样做才不会让两个小球碰撞到一起。
		 * 接下来，计算出 x,y 轴的加速度 ax,ay。
		 * 下面要注意了，本例中，不仅 ball1 要向 ball0 弹性运动，而且 ball0 还必需离开 ball1，加速度的方向相反。
		 * 只需要将 ax 和 ay 加到 ball1 的速度向量中，再从 ball0 的速度向量中将它们减去即可！
		 * 这样就免去了计算两次的麻烦。大家也许认为这样做，就相当于把最终的加速度扩大了两倍。
		 * 是的，您说得没错。为了弥补这一点，我们将 spring 的值设置得比平时小一些。
		 * */
		private function onEnterFrame(event:Event):void
		{
			for (var i:uint=0; i < numBalls - 1; i++)
			{
				var ball0:Ball=balls[i];
				for (var j:uint=i + 1; j < numBalls; j++)
				{
					var ball1:Ball=balls[j];
					var dx:Number=ball1.x - ball0.x;
					var dy:Number=ball1.y - ball0.y;
					var dist:Number=Math.sqrt(dx * dx + dy * dy);
					var minDist:Number=ball0.radius + ball1.radius;
					if (dist < minDist)
					{
						/**
						 * 代码中使用 Math.atan2 计算夹角，然后再用 Math.cos 和 Math.sin 求出目标点：
						 * var angle:Number = Math.atan2(dy, dx);
						 * var tx:Number = ball0.x + Math.cos(angle) * minDist;
						 * var ty:Number = ball0.y + Math.sin(angle) * minDist;
						 * 但是大家不要忘记，正弦是对边与斜边之比，而余弦是邻边与斜边之比。
						 * 请注意，该角的对边就是 dy，邻边就是 dx，而斜边就是 dist。
						 * 所以，我们实际上可以将这三行代码缩短为两行：
						 * var tx:Number = ball0.x + dx / dist * minDist;
						 * var ty:Number = ball0.y + dy / dist * minDist;
						 * */
//						var angle:Number=Math.atan2(dy, dx);
//						var tx:Number=ball0.x + Math.cos(angle) * minDist;
//						var ty:Number=ball0.y + Math.sin(angle) * minDist;
						var tx:Number=ball0.x + dx / dist * minDist;
						var ty:Number=ball0.y + dy / dist * minDist;
						var ax:Number=(tx - ball1.x) * spring;
						var ay:Number=(ty - ball1.y) * spring;
						ball0.vx-=ax;
						ball0.vy-=ay;
						ball1.vx+=ax;
						ball1.vy+=ay;
					}
				}
			}
			for (i=0; i < numBalls; i++)
			{
				var ball:Ball=balls[i];
				move(ball);
			}
		}

		private function move(ball:Ball):void
		{
			ball.vy+=gravity;
			ball.x+=ball.vx;
			ball.y+=ball.vy;
			if (ball.x + ball.radius > stage.stageWidth)
			{
				ball.x=stage.stageWidth - ball.radius;
				ball.vx*=bounce;
			}
			else if (ball.x - ball.radius < 0)
			{
				ball.x=ball.radius;
				ball.vx*=bounce;
			}
			if (ball.y + ball.radius > stage.stageHeight)
			{
				ball.y=stage.stageHeight - ball.radius;
				ball.vy*=bounce;
			}
			else if (ball.y - ball.radius < 0)
			{
				ball.y=ball.radius;
				ball.vy*=bounce;
			}
		}
	}
}